#ifndef POST_PROCESSING_PIPELINE
#define POST_PROCESSING_PIPELINE

#include <d3d11.h>
#include <vector>
#include "CComPtrEx.h"

struct csCopyTextureBuffer
{
	UINT textureSize[2];
	UINT dispatchDimensions[2];
	float exposure;
	UINT inputsCount;
	UINT secondTextureSize[2];
};

#define LUMINANCE_HISTORY_LENGTH 16

class D3D11Client;
class PostProcessingPipeline
{
protected:
	D3D11Client * m_gc;
	CComPtrEx<ID3D11Texture2D> m_inputTexture;

	D3D11Client * GetClient() { return m_gc; }
public:
	PostProcessingPipeline(D3D11Client * gc, CComPtrEx<ID3D11Texture2D>& inputTexture)
		: m_gc(gc), m_inputTexture(inputTexture) {}
	virtual ~PostProcessingPipeline() {}
	virtual bool Init(CComPtrEx<ID3D11Texture2D>& outputTexture) = 0;
	virtual void RunPipeline(double interval, bool isPause) = 0;
	virtual float GetLuminance() = 0;
};

class PSPostProcessingPipeline : public PostProcessingPipeline
{
private:
	CComPtrEx<ID3D11ShaderResourceView> m_inputTextureSRV;
	CComPtrEx<ID3D11Texture2D> m_outputTexture;	
	CComPtrEx<ID3D11RenderTargetView> m_outputTextureRTV;
	UINT m_width, m_height;
	UINT m_currentBuffer;

	float m_currentLuminance;
	float m_adaptedLuminance;
	float m_luminanceHistory[LUMINANCE_HISTORY_LENGTH];

	struct CalcLuminance
	{
		UINT width, height;
		CComPtrEx<ID3D11Texture2D> texture;
		CComPtrEx<ID3D11ShaderResourceView> srv;
		CComPtrEx<ID3D11RenderTargetView> rtv;
	};
	std::vector<CalcLuminance> m_calculateLuminanceData;

	CComPtrEx<ID3D11Buffer> m_csCopyTextureBuffer;

	CComPtrEx<ID3D11Texture2D> m_luminanceTexture;
	CComPtrEx<ID3D11ShaderResourceView> m_luminanceTextureSRV;
	CComPtrEx<ID3D11Texture2D> m_luminanceTextureRW[3];

	CComPtrEx<ID3D11VertexShader> m_passThroughVS;
	CComPtrEx<ID3D11InputLayout> m_layout;
	CComPtrEx<ID3D11Buffer> m_quadBuffer;

	CComPtrEx<ID3D11Texture2D> m_bloomTexture;
	CComPtrEx<ID3D11ShaderResourceView> m_bloomTextureSRV;
	CComPtrEx<ID3D11RenderTargetView> m_bloomTextureRTV;

	CComPtrEx<ID3D11Texture2D> m_lightStreaksTexture;
	CComPtrEx<ID3D11ShaderResourceView> m_lightStreaksTextureSRV;
	CComPtrEx<ID3D11RenderTargetView> m_lightStreaksTextureRTV;

	CComPtrEx<ID3D11Texture2D> m_lightStreaksTempTexture;
	CComPtrEx<ID3D11ShaderResourceView> m_lightStreaksTempTextureSRV;
	CComPtrEx<ID3D11RenderTargetView> m_lightStreaksTempTextureRTV;

	CComPtrEx<ID3D11Texture2D> m_gaussianBlurTempTexture;
	CComPtrEx<ID3D11ShaderResourceView> m_gaussianBlurTempTextureSRV;
	CComPtrEx<ID3D11RenderTargetView> m_gaussianBlurTempTextureRTV;

	CComPtrEx<ID3D11PixelShader> m_calculateLuminancePS;
	CComPtrEx<ID3D11PixelShader> m_reducePS;
	CComPtrEx<ID3D11PixelShader> m_calculateBloomTexturePS;
	CComPtrEx<ID3D11PixelShader> m_calculateLightStreaksTexturePS;
	CComPtrEx<ID3D11PixelShader> m_createLightStreaksTexturePS;
	CComPtrEx<ID3D11PixelShader> m_gaussianBlurVerticalPassPS;
	CComPtrEx<ID3D11PixelShader> m_gaussianBlurHorizontalPassPS;
	CComPtrEx<ID3D11PixelShader> m_copyTextureWithExposurePS;
public:
	PSPostProcessingPipeline(D3D11Client * d3d, CComPtrEx<ID3D11Texture2D>& inputTexture);
	virtual ~PSPostProcessingPipeline() {}
	virtual bool Init(CComPtrEx<ID3D11Texture2D>& outputTexture);
	virtual void RunPipeline(double interval, bool isPause);

	virtual float GetLuminance() {return m_currentLuminance; }
};

#endif //POST_PROCESSING_PIPELINE
